﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SlimDX.D3DCompiler;
using SlimDX;
using SlimDX.Direct3D11;
using SlimDX.DXGI;
using System.Runtime.InteropServices;
using System.Drawing;
using Apparat.ShaderManagement;

namespace Apparat.Renderables
{
    public class TextureQuad : Renderable
    {
        SlimDX.Direct3D11.Buffer vertexBuffer;
        Vector3 minXminY, minXmaxY, maxXminY, maxXmaxY;
        DataStream vertices;
        int numVertices = 0;
        int vertexStride = 0;

        Color4 diffuse = new Color4(1, 0, 1, 0);
        Texture2D texture;


        ShaderResourceView m_textureView;

        public TextureQuad(Vector3 min, Vector3 max)
        {
            float y = (min.Y + max.Y) / 2.0f;
            minXminY = min;
            maxXmaxY = max;
            minXmaxY = new Vector3(min.X, y, max.Z);
            maxXminY = new Vector3(max.X, y, min.Z);

            numVertices = 6;
            vertexStride = 20;
            int SizeOfVertexBufferInBytes = numVertices * vertexStride;
            vertices = new DataStream(SizeOfVertexBufferInBytes, true, true);

            vertices.Write(min); vertices.Write(new Vector2(0, 1));
            vertices.Write(minXmaxY); vertices.Write(new Vector2(0, 0));
            vertices.Write(max); vertices.Write(new Vector2(1, 0));

            vertices.Write(max); vertices.Write(new Vector2(1, 0));
            vertices.Write(maxXminY); vertices.Write(new Vector2(1, 1));
            vertices.Write(min); vertices.Write(new Vector2(0, 1));

            vertices.Position = 0;

            // create the vertex buffer
            vertexBuffer = new SlimDX.Direct3D11.Buffer(DeviceManager.Instance.device,
                vertices,
                SizeOfVertexBufferInBytes,
                ResourceUsage.Default,
                BindFlags.VertexBuffer,
                CpuAccessFlags.None,
                ResourceOptionFlags.None,
                0);
        }

        public TextureQuad(Vector3 min, Vector3 max, string PicturePath)
            : this(min, max)
        {
            try
            {
                LoadPicture(PicturePath);
            }
            catch (Exception ex)
            {
            }
        }

        public void LoadPicture(string path)
        {
            texture = Texture2D.FromFile(DeviceManager.Instance.device, path);
            m_textureView = new ShaderResourceView(DeviceManager.Instance.device, texture);
        }

        public void SetTexture(Bitmap bmp)
        {

            System.Drawing.Imaging.BitmapData bitmapData = bmp.LockBits(
              new Rectangle(0, 0, bmp.Width, bmp.Height),
              System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

            DataStream dataStream = new DataStream(bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, true, false);
            DataRectangle dataRectangle = new DataRectangle(bitmapData.Stride, dataStream);

            try
            {
                //Load the texture
                texture = new Texture2D(DeviceManager.Instance.device, new Texture2DDescription()
                {
                    BindFlags = BindFlags.ShaderResource,
                    CpuAccessFlags = CpuAccessFlags.None,
                    Format = Format.B8G8R8A8_UNorm,
                    OptionFlags = ResourceOptionFlags.None,
                    MipLevels = 1,
                    Usage = ResourceUsage.Immutable,
                    Width = bmp.Width,
                    Height = bmp.Height,
                    ArraySize = 1,
                    SampleDescription = new SampleDescription(1, 0)
                }, dataRectangle);
            }
            finally
            {
                //Free bitmap-access resources
                dataStream.Dispose();
                bmp.UnlockBits(bitmapData);
            }


            m_textureView = new ShaderResourceView(DeviceManager.Instance.device, texture);
        }

        public void SetColor(System.Drawing.Color color)
        {
            float r = (float)(color.R / 255.0f);
            float g = (float)((float)color.G / 255.0f);
            float b = (float)(color.B / 255.0f);


            Color4 col = new Color4(1, (float)(color.R / 255.0f), (float)((float)color.G / 255.0f), (float)(color.B / 255.0f));
            diffuse = col;
        }

        EffectWrapperTextureEffect ew = ShaderManager.Instance.textureEffect;

        public override void Render()
        {
            Matrix ViewPerspective = CameraManager.Instance.ViewPerspective;
            Matrix WorldViewPerspective = this.transform * ViewPerspective;

            ew.tmat.SetMatrix(WorldViewPerspective);

            // configure the Input Assembler portion of the pipeline with the vertex data
            DeviceManager.Instance.context.InputAssembler.InputLayout = ew.layout;
            DeviceManager.Instance.context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;

            DeviceManager.Instance.context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, vertexStride, 0));

            ew.textureResourceVariable.SetResource(m_textureView);
            ew.technique = ew.effect.GetTechniqueByName("Render");

            EffectTechniqueDescription techDesc;
            techDesc = ew.technique.Description;

            for (int p = 0; p < techDesc.PassCount; ++p)
            {
                ew.technique.GetPassByIndex(p).Apply(DeviceManager.Instance.context);
                DeviceManager.Instance.context.Draw(numVertices, 0);
            }
        }

        public override void Dispose()
        {

        }

        public override SlimDX.Matrix Transform
        {
            get
            {
                return transform;
            }
            set
            {
                transform = value;
            }
        }
    }
}
